package com.sztx.pay.center.core.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.mortbay.log.Log;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import com.alibaba.fastjson.JSONObject;
import com.sztx.pay.center.common.util.Constance;
import com.sztx.pay.center.common.util.Constance.CardType;
import com.sztx.pay.center.common.util.Constance.PayFlowState;
import com.sztx.pay.center.common.util.Constance.PayFlowType;
import com.sztx.pay.center.common.util.Constance.TradeOrderType;
import com.sztx.pay.center.common.util.Constance.UserActType;
import com.sztx.pay.center.common.util.CurrencyUtil;
import com.sztx.pay.center.common.util.JFUtils;
import com.sztx.pay.center.common.util.JfConfigUtil;
import com.sztx.pay.center.core.service.AccountService;
import com.sztx.pay.center.core.service.ActService;
import com.sztx.pay.center.core.service.BillnoService;
import com.sztx.pay.center.core.service.OrderMappingService;
import com.sztx.pay.center.core.service.PayCoreCallBack;
import com.sztx.pay.center.core.service.PayCoreService;
import com.sztx.pay.center.core.service.SettleService;
import com.sztx.pay.center.core.service.UserInfoService;
import com.sztx.pay.center.core.service.bean.BatchPayCoreTransferReq;
import com.sztx.pay.center.core.service.bean.BatchTransferDetail;
import com.sztx.pay.center.core.service.bean.ConfirmPoJo;
import com.sztx.pay.center.core.service.bean.PayCoreTradeInfo;
import com.sztx.pay.center.core.service.bean.PayCoreTransferResult;
import com.sztx.pay.center.core.service.bean.PayeeInfo;
import com.sztx.pay.center.core.service.bean.SettleRequest;
import com.sztx.pay.center.core.service.bean.rpc.SettleRuleListRequest;
import com.sztx.pay.center.core.service.bean.rpc.SettleRuleListResponse;
import com.sztx.pay.center.core.service.bean.rpc.SettleRuleRequest;
import com.sztx.pay.center.core.service.bean.rpc.SettleRuleResponse;
import com.sztx.pay.center.core.service.util.SettleState;
import com.sztx.pay.center.core.service.util.SettleTradeType;
import com.sztx.pay.center.core.service.util.SettleType;
import com.sztx.pay.center.dataaccess.dao.mysql.OrderB2cMysqlDAO;
import com.sztx.pay.center.dataaccess.dao.mysql.SettleOrderMysqlDAO;
import com.sztx.pay.center.dataaccess.dao.mysql.SettleRuleMysqlDAO;
import com.sztx.pay.center.dataaccess.dao.mysql.SettleRulePersonalMysqlDAO;
import com.sztx.pay.center.dataaccess.dao.redis.LockRedisDAO;
import com.sztx.pay.center.dataaccess.domain.OrderB2cDO;
import com.sztx.pay.center.dataaccess.domain.SettleOrderDO;
import com.sztx.pay.center.dataaccess.domain.SettleRuleIndexDO;
import com.sztx.pay.center.dataaccess.domain.SettleRulePersonalDO;
import com.sztx.pay.center.dataaccess.domain.SettleRulePersonalListDO;
import com.sztx.pay.center.dataaccess.domain.UserActDO;
import com.sztx.pay.center.dataaccess.domain.UserInfoDO;
import com.sztx.pay.center.dataaccess.entity.QuerySettle;
import com.sztx.se.common.exception.BusinessException;
import com.sztx.se.common.util.StringUtil;
import com.sztx.se.common.util.date.DateUtil;
import com.sztx.se.common.util.validate.ValidateUtil;
import com.sztx.se.core.context.SpringContextHolder;
import com.sztx.se.core.service.impl.BaseServiceImpl;
import com.sztx.se.dataaccess.mysql.config.PageQuery;
import com.sztx.se.rpc.dubbo.client.DubboClientFactory;
import com.sztx.usercenter.rpc.api.domain.out.RegisterPlatformVO;
import com.sztx.usercenter.rpc.api.domain.out.UserVO;
import com.sztx.usercenter.rpc.api.service.QueryUserInfoService;
import com.sztx.usercenter.rpc.api.service.RegisterPlatformService;

@Service
public class SettleServiceImpl extends BaseServiceImpl implements SettleService, PayCoreCallBack {

	private static final Logger log = LoggerFactory.getLogger(SettleServiceImpl.class);
	
	@Autowired
	private DubboClientFactory dubbo;

	@Autowired
	private BillnoService billnoService;

	@Autowired
	private PayCoreService payCoreService;

	@Autowired
	private AccountService accountService;

	@Autowired
	private SettleRulePersonalMysqlDAO rulePersonalDao;

	@Autowired
	private SettleRuleMysqlDAO ruleDao;

	@Autowired
	private SettleOrderMysqlDAO settleOrderDao;
	
	@Autowired
	private OrderB2cMysqlDAO b2cOrderDao;

	@Autowired
	OrderMappingService orderMappingService;
	
	@Autowired
	private ActService actService;
	
	@Autowired
	private UserInfoService userInfoService;
	
	@Autowired
	private LockRedisDAO lockRedisDAO;
	@Override
	public ConfirmPoJo settleNow(SettleRequest request, String serviceName) {
		// 验证参数
		checkParams(request);

		// 按照收款方信息，拆分成多个结算订单
		List<SettleOrderDO> orders = initSettleOrder(SettleType.NOW.getValue(), request, serviceName);

		// 保存结算信息
		settleOrderDao.saveAll(orders);

		// 资金操作
		for (SettleOrderDO order : orders) {
			settleOrderDao.updateState(order.getSettleOrderId(), SettleState.SETTLING.getValue());
		}
		return transfer(request.getOrderId(), orders);
	}

	@Override
	public void settleLatter(SettleRequest request, String serviceName) {
		// 验证参数
		checkParams(request);
		// 按照收款方信息，拆分成多个结算订单
		List<SettleOrderDO> orders = initSettleOrder(SettleType.LATTER.getValue(), request, serviceName);
		// 保存结算信息
		settleOrderDao.saveAll(orders);
	}

	@Override
	public long calculateHandlingFee(SettleTradeType tradeType, SettleType settleType, String userId, long amount,String channelId,String bankId,CardType cardType) {
		long handlingFee = 0;
		//添加金额小于10分的交易手续费为0
//		if(amount <= 10 && tradeType == SettleTradeType.TRADE){
//			return handlingFee;
//		}
		
		if(JFUtils.isJFChannel(channelId) && checkInWhiteList(userId)){
			return handlingFee;
		}
		
		if(JFUtils.isJFChannel(channelId) && StringUtil.isNotBlank(bankId)){
			return getJFPayFee(tradeType,amount, bankId, cardType);
		}
		
		
		SettleRulePersonalDO rule = getRule(tradeType, settleType, userId,  channelId,1);
		if(rule == null){
			return handlingFee;
		}
		if (rule.getFeeType() == 2) {
			handlingFee = rule.getFeeAmount().longValue();
			handlingFee = handlingFee > amount ? amount : handlingFee;
		} else {
			//handlingFee = (long) (amount * (rule.getFeeAmount() / 100));
			BigDecimal multiply = CurrencyUtil.multiply((double)amount,rule.getFeeAmount());
			BigDecimal divide = CurrencyUtil.divide("100",multiply.toString());
			handlingFee = divide.longValue();
			
			if (rule.getLowerLimit() != -1) {
				handlingFee = handlingFee < rule.getLowerLimit() ? rule.getLowerLimit() : handlingFee;
			}
			if (rule.getUpperLimit() != -1) {
				handlingFee = handlingFee > rule.getUpperLimit() ? rule.getUpperLimit() : handlingFee;
			}
		}
		return handlingFee > amount ? amount : handlingFee;
	}
	
	
//	public static void main(String[] args) {
//		long amount = 10000l;
//		BigDecimal multiply = CurrencyUtil.multiply((double)amount,0.29);
//		System.out.println(multiply.toString());
//		BigDecimal divide = CurrencyUtil.divide("110",multiply.toString());
//		//long handlingFee = (long) (10000 * 0.29 / 100);
//		System.out.println(divide.longValue());
//		System.out.println(new BigDecimal("2900").divide(new BigDecimal("110"), 2, BigDecimal.ROUND_HALF_UP));
//	}

	@Override
	public void callPayResult(PayCoreTradeInfo tradeInfo) {
		if (tradeInfo != null && tradeInfo.getBatchTransferResult() != null && !tradeInfo.getBatchTransferResult().isEmpty()) {
			updateSettleResult(tradeInfo.getBatchTransferResult());

			callResult(tradeInfo.getBatchTransferResult());
		}
	}
	
	private void callResult(List<PayCoreTransferResult> transferResult) {
		List<String> settleOrderIds = new ArrayList<String>();
		for (PayCoreTransferResult result : transferResult) {
			settleOrderIds.add(result.getReferOrderId());
		}

		List<String> orderIds = settleOrderDao.getCallBackOrderIds(settleOrderIds);
		for (String orderId : orderIds) {
			List<SettleOrderDO> orders = settleOrderDao.getSettleOrdersByOrderId(orderId);
			if (StringUtil.isBlank(orders.get(0).getServiceName())) {
				break;
			}
			PayCoreTradeInfo payResult = new PayCoreTradeInfo();
			payResult.setReferOrderId(orderId);
			PayFlowState state = null;
			for (SettleOrderDO order : orders) {
				if (order.getState() == SettleState.EXCEPTION.getValue()) {
					state = PayFlowState.EXCEPTION;
					break;
				} else if (order.getState() == SettleState.SUCCESS.getValue()) {
					if (state == null || state == PayFlowState.SUCCESS) {
						state = PayFlowState.SUCCESS;
					} else {
						state = PayFlowState.EXCEPTION;
						break;
					}
				} else if (order.getState() == SettleState.FAIL.getValue()) {
					if (state == null) {
						state = PayFlowState.FAIL;
					} else {
						state = PayFlowState.EXCEPTION;
					}
				} else if (order.getState() == SettleState.SETTLING.getValue()) {
					if (state == null) {
						state = PayFlowState.PAYING;
					}
				}
			}
			payResult.setPayFlowState(state);

			PayCoreCallBack payCoreCallBack = SpringContextHolder.applicationContext.getBean(orders.get(0).getServiceName(), PayCoreCallBack.class);
			if (payCoreCallBack == null) {
				LOG.error("未找到" + orders.get(0).getServiceName() + "服务");
				return;
			}
			payCoreCallBack.callPayResult(payResult);
		}
	}

	private void updateSettleResult(List<PayCoreTransferResult> result) {
		for (PayCoreTransferResult item : result) {
			try {
				int state;
				switch (item.getTradeSataus().getCode()) {
				case 3:
					state = SettleState.SUCCESS.getValue();
					break;
				case 4:// 失败
					state = SettleState.FAIL.getValue();
					break;
				case 5:// 异常
					state = SettleState.EXCEPTION.getValue();
					break;
				default:
					state = SettleState.SETTLING.getValue();
					continue;
				}
				if (!item.getReferOrderId().endsWith("_HF")) {
					settleOrderDao.updateSettleResult(item.getReferOrderId(), item.getPayFlowNo(), item.getAmount() == null ? 0 : item.getAmount().longValue(),
							new Date(), state, item.getTradeDesc());
					//sendSettleInfo(item.getReferOrderId());
				} else {
					String settleOrderId = item.getReferOrderId().substring(0, item.getReferOrderId().lastIndexOf("_"));
					int update = settleOrderDao.updateHandlingFeeResult(settleOrderId, state);
					if (update > 0) {
						settleOrderDao.updateSettleResult(settleOrderId, item.getPayFlowNo(), 0, new Date(), state, item.getTradeDesc());
						//sendSettleInfo(settleOrderId);
					}
				}
			} catch (Exception ex) {
				log.error(String.format("更新结算结果异常,settleOrderId=%s,status=%s", item.getReferOrderId(), item.getTradeSataus().getCode()), ex);
				continue;
			}
		}
	}

	public ConfirmPoJo transfer(String orderId, List<SettleOrderDO> orders) {
		
		
		long totalAmount = 0l;
		BatchPayCoreTransferReq transferInfo = new BatchPayCoreTransferReq();
		List<BatchTransferDetail> payeeInfoList = new ArrayList<BatchTransferDetail>();
		
		transferInfo.setBatchOrderId(orderId);
		UserActDO payerUserAct = null;
		String payerUserId = null;
		if(!CollectionUtils.isEmpty(orders)){
			payerUserId = orders.get(0).getPayerUser();
			payerUserAct = findUserAct(payerUserId, UserActType.TRADE);
		}
		
		
		for (SettleOrderDO settleOrderDO : orders) {
			long settleAmount = settleOrderDO.getSettleAmount();
			BatchTransferDetail batchTransferDetail = new BatchTransferDetail();
			String subSettleMappingOrderId = orderMappingService.addMappingOrder(settleOrderDO.getSettleOrderId(), (byte) PayFlowType.BALANCE_BATCH_TRASFER.getCode());
			
			batchTransferDetail.setAmount(settleAmount);
			batchTransferDetail.setAttach(settleOrderDO.getAttach());
			batchTransferDetail.setSubOrderNo(subSettleMappingOrderId);
			batchTransferDetail.setTradeOrderType(TradeOrderType.valueOf(settleOrderDO.getTradeOrderType()));
			batchTransferDetail.setOriginOrderId(settleOrderDO.getOrderId());
			batchTransferDetail.setPayerActNo(payerUserAct.getActNo());
			batchTransferDetail.setPayerAcType(UserActType.valueOf(payerUserAct.getActType()));
			batchTransferDetail.setPayerUserId(payerUserId);
			batchTransferDetail.setPayerUserType(payerUserAct.getUserType());
			batchTransferDetail.setBusinessType(settleOrderDO.getBusinessType());
			// 设置收款人信息
			if (Constance.USER_REBATE.equals(settleOrderDO.getPayeeUser())) {
				batchTransferDetail.setPayeeUserId(Constance.USER_REBATE);
				batchTransferDetail.setPayeeUserType(1);
				batchTransferDetail.setPayeeActNo(Constance.ACT_REBATE);
				batchTransferDetail.setPayeeActType(UserActType.CASH);
			} else if (Constance.USER_PROFIT.equals(settleOrderDO.getPayeeUser())) {
				batchTransferDetail.setPayeeUserId(Constance.USER_PROFIT);
				batchTransferDetail.setPayeeUserType(1);
				batchTransferDetail.setPayeeActNo(Constance.ACT_PROFIT);
				batchTransferDetail.setPayeeActType(UserActType.CASH);
			} else {
				UserActDO payee = findUserAct(settleOrderDO.getPayeeUser(), UserActType.CASH);
				batchTransferDetail.setPayeeUserId(payee.getUserId());
				batchTransferDetail.setPayeeUserType(payee.getUserType());
				batchTransferDetail.setPayeeActType(UserActType.valueOf(payee.getActType()));
				batchTransferDetail.setPayeeActNo(payee.getActNo());
			}
			totalAmount += settleAmount;
			payeeInfoList.add(batchTransferDetail);
		}
		
		settleOrderDao.updateSettleResultByOrderId(orderId, new Date(), SettleState.SETTLING.getValue(), SettleState.SETTLING.getDesc());
		
		transferInfo.setTotalAmount(totalAmount);
		transferInfo.setPayeeInfoList(payeeInfoList);
		String resultMsg = SettleState.SUCCESS.getDesc();
		int resultState = SettleState.SUCCESS.getValue();
		int payFlowState = PayFlowState.SUCCESS.getCode();
		try {
			log.info("结算批量转账:" + JSONObject.toJSONString(transferInfo));
			payCoreService.batchBalanceTransfer(transferInfo);
		} catch (BusinessException e) {
			resultMsg = e.getMessage();
			resultState = SettleState.FAIL.getValue();
			payFlowState = PayFlowState.FAIL.getCode();
			log.info("",e);
			log.info(String.format("结算订单失败:[%s]", orderId));
		} catch (Exception e) {
			resultMsg = SettleState.EXCEPTION.getDesc();
			resultState = SettleState.EXCEPTION.getValue();
			payFlowState = PayFlowState.EXCEPTION.getCode();
			log.info("",e);
			log.info(String.format("结算订单失败:[%s]", orderId));
		}
		
		//更新结算订单状态
		settleOrderDao.updateSettleResultByOrderId(orderId, new Date(), resultState, resultMsg);
		
		PayCoreTradeInfo payResult = new PayCoreTradeInfo();
		
		payResult.setReferOrderId(orderId);
		payResult.setPayFlowState(PayFlowState.valueOf(payFlowState));
		payResult.setPayFlowDesc(resultMsg);
		
		PayCoreCallBack payCoreCallBack = SpringContextHolder.applicationContext.getBean(orders.get(0).getServiceName(), PayCoreCallBack.class);
		payCoreCallBack.callPayResult(payResult);
		ConfirmPoJo resp = new ConfirmPoJo();
		resp.setState(payFlowState);
		resp.setMsg(resultMsg);
		return resp;
	}


	private UserActDO findUserAct(String userId, UserActType userActType) {
		UserInfoDO userInfoDO = userInfoService.findUserInfo(userId);
		UserActDO userActDO = actService.findUserAct(userId, userActType);
		userActDO.setUserType(userInfoDO.getUserType());
		return userActDO;
	}

	private void calculateHandlingFee(SettleOrderDO order) {
		SettleRulePersonalDO rule = getRule(SettleTradeType.TRADE, SettleType.valueOf(order.getSettleType()), order.getPayeeUser(), null,1);
		// 计算手续费
		if (rule == null) {
			// 无手续费
			order.setSettleRuleId(0);
			order.setHandlingFee(0);
		} else {
			order.setSettleRuleId(rule.getId());
			if (rule.getFeeType() == 2) {
				if (order.getSettleAmount() < rule.getFeeAmount()) {
					order.setHandlingFee(order.getSettleAmount());
				} else {
					order.setHandlingFee(rule.getFeeAmount().longValue());
				}
			} else {
				long handlingFee = (long) (order.getSettleAmount() * (rule.getFeeAmount() / 100));
				handlingFee = handlingFee < rule.getLowerLimit() ? rule.getLowerLimit() : handlingFee > rule.getUpperLimit() ? rule.getUpperLimit()
						: handlingFee;
				order.setHandlingFee(handlingFee);
			}
		}
	}

	private List<SettleOrderDO> initSettleOrder(int settleType, SettleRequest request, String serviceName) {
		if (!request.isPerPayeeHandingFee() && request.getHandingFee() > 0) {
			PayeeInfo hfPayeeInfo = new PayeeInfo();
			hfPayeeInfo.setPayeeUser(Constance.USER_PROFIT);
			hfPayeeInfo.setAmount(request.getHandingFee());
			hfPayeeInfo.setTradeOrderType(TradeOrderType.TRADE_FEE);
			request.getPayeeInfo().add(hfPayeeInfo);
		}
		List<SettleOrderDO> orders = new ArrayList<SettleOrderDO>();
		for (PayeeInfo payee : request.getPayeeInfo()) {
			String settleOrderId = billnoService.nextSettleNo();
			SettleOrderDO order = new SettleOrderDO();
			order.setSettleOrderId(settleOrderId);
			order.setOrderId(request.getOrderId());
			order.setSettleType(settleType);
			order.setCreateTime(new Date());
			order.setPayerUser(request.getPayerUser());
			order.setPayeeUser(payee.getPayeeUser());
			order.setSettleAmount(payee.getAmount());
			order.setState(SettleState.UNSETTLE.getValue());
			order.setAttach(request.getAttach());
			order.setServiceName(serviceName);
			//新增交易类型
			order.setTradeOrderType(payee.getTradeOrderType().getCode());
			//新增业务类型
			order.setBusinessType(request.getBusinessType());
			if (request.isPerPayeeHandingFee()) {
				// 计算手续费
				calculateHandlingFee(order);
			}

			orders.add(order);
		}
		return orders;
	}

	private void checkParams(SettleRequest request) {
		ValidateUtil.isNotBlank(request.getOrderId(), "交易订单号不能为空");
		ValidateUtil.isNotBlank(request.getPayerUser(), "付款人倍棒账号不能为空");
		for (PayeeInfo item : request.getPayeeInfo()) {
			ValidateUtil.isNotBlank(item.getPayeeUser(), "收款人倍棒账号不能为空");
			ValidateUtil.gt((int) item.getAmount(), 0, "收款人结算金额不能小于等于0");
		}
	}
//	private void sendSettleInfo(String settleOrderId) {
//		SettleOrderDO order = settleOrderDao.getSettleOrderBySettleOrderId(settleOrderId);
//		if (order.getState() == SettleState.SUCCESS.getValue() && !order.getPayeeUser().equals(Constance.ACT_SZTX_PROFIT) && !order.getPayeeUser().equals(Constance.ACT_SZTX_REBATE)) {
//			OrderRequest req = new OrderRequest();
//			
//			OrderB2cDO b2cOrder = b2cOrderDao.findById(order.getOrderId());
//			if (order.getHandlingFee() > 0) {
//				// 结算时计算手续费
//				req.setHandlingFee((int) order.getHandlingFee());
//				req.setAmount((int) order.getSettleAmount());
//				req.setPayAmount((int) order.getFundsToAccount());
//			} else {
//				// 确认收货时传入手续费
//				if (order.getPayeeUser().equals(b2cOrder.getPayeeUserId())) {
//					// 收款人是b2c订单的收款人
//					req.setHandlingFee(b2cOrder.getFee());
//					req.setAmount((int) (order.getSettleAmount() + b2cOrder.getFee()));
//					req.setPayAmount((int) order.getFundsToAccount());
//				} else {
//					// 收款人为b2c订单的其他结算收款人
//					req.setHandlingFee(0);
//					req.setAmount((int) order.getSettleAmount());
//					req.setPayAmount((int) order.getFundsToAccount());
//				}
//			}
//			OrderRpcService orderRpcService = dubbo.getDubboClient("orderRpcService");
//			
//			req.setTranOrderId(order.getSettleOrderId());
//			req.setRelateOrderId(b2cOrder.getOrderId());
//			req.setPayOrderId(order.getPayFlowNo());
//			req.setOrderType(OrderType.SETTLE.getIndex());
//			req.setCustomer(order.getPayerUser());// 付款方
//			req.setMerchant(order.getPayeeUser());// 收款方
//			req.setGoodsName("结算");
//			orderRpcService.order(req);
//		}
//	}
	
	private void updateB2CSettleTime(String orderId){
		OrderB2cDO orderB2cDO = new OrderB2cDO();
		orderB2cDO.setTradeOrderId(orderId);
		orderB2cDO.setSettleTime(new Date());
		b2cOrderDao.updateInfo(orderB2cDO );
	}

	private SettleRulePersonalDO getRule(SettleTradeType tradeType, SettleType settleType, String userId,String channelId,Integer state) {
		if(channelId == null && userId != null){
			channelId = getChannelIdByUserId(userId);
		}
		
		SettleRulePersonalDO settleRulePersonalDO = new SettleRulePersonalDO();
		settleRulePersonalDO.setUserId(userId);
		if(tradeType != null){
			settleRulePersonalDO.setTradeType((byte)tradeType.getValue());
		}
		if(state != null){
			settleRulePersonalDO.setState((byte)state.intValue());
		}
		settleRulePersonalDO.setChannelId(channelId);
		if(settleType != null){
			settleRulePersonalDO.setSettleType((byte)settleType.getValue());
		}
		// 根据收款人，查询交易结算规则
		List<SettleRulePersonalDO> ruleList = rulePersonalDao.getRule(settleRulePersonalDO );
		// 计算手续费
		if (ruleList == null) {
			log.info("not find the rule,tradeType="+tradeType.getValue()+",userId"+userId+",channelId="+channelId+",settleType="+settleType);
			// 无手续费
			return null;
		} else {
			SettleRulePersonalDO commonRule = null;
			SettleRulePersonalDO channelRule = null;
			SettleRulePersonalDO personRule = null;
			for (SettleRulePersonalDO settleRule : ruleList) {
				if(!StringUtil.isBlank(settleRule.getUserId()) && settleRule.getUserId().equals(userId)){
					personRule = settleRule;
				}else if(!StringUtil.isBlank(settleRule.getChannelId()) && settleRule.getChannelId().equals(channelId)){
					channelRule = settleRule;
				}else if(StringUtil.isBlank(settleRule.getChannelId())){
					commonRule = settleRule;
				}
			}
			SettleRulePersonalDO rule = null;
			if(personRule != null){
				rule = personRule;
			}else if(channelRule != null){
				rule = channelRule;
			}else if(commonRule != null){
				rule = commonRule;
			}else{
				log.info("not find the rule,tradeType="+tradeType.getValue()+",userId"+userId+",channelId="+channelId+",settleType="+settleType);
				// 无手续费
				return null;
			}
			return rule;
		}
	}


	private String getChannelName(String channelId){
		//根据渠道ID查询名称
		RegisterPlatformService registerPlatformService = (RegisterPlatformService) dubbo.getDubboClient("registerPlatformService");
		RegisterPlatformVO registerPlatformVO = registerPlatformService.getRegisterPlatform(Integer.parseInt(channelId));
		if(registerPlatformVO == null){
			throw new BusinessException("渠道ID查询详情失败!");
		}
		String channelName = registerPlatformVO.getRegisterPlatformName();
		return channelName;
	}
	private String getChannelIdByUserId(String userId){
		QueryUserInfoService queryUserInfoService = (QueryUserInfoService)dubbo.getDubboClient("queryUserInfoService");
		UserVO userInfo = queryUserInfoService.getUserInfo(userId);
		String channelId = null;
		if(userInfo != null){
			channelId = String.valueOf(userInfo.getRegisterPlatformId());
		}else{
			throw new BusinessException("查询用户渠道信息失败!");
		}
		return channelId;
	}

	@Override
	public int configSettleRule(SettleRuleRequest req){
		if(!StringUtil.isBlank(req.getUserId()) && StringUtil.isBlank(req.getChannelId())){
			String channelId = getChannelIdByUserId(req.getUserId());
			req.setChannelId(channelId);
		}
		
		
		SettleRulePersonalDO rule = new SettleRulePersonalDO();
		rule.setFeeAmount(req.getFeeAmount());
		rule.setFeeType((byte)req.getFeeType());
		rule.setLowerLimit((int)req.getLowerLimit());
		rule.setSettleType((byte)req.getSettleType());
		rule.setState((byte)req.getState());
		rule.setTradeType((byte)req.getTradeType());
		rule.setUpperLimit((int)req.getUpperLimit());
		rule.setAttach(req.getAttach());
		rule.setOperator(req.getOperator());
		rule.setChannelId(req.getChannelId());
		
		//根据渠道ID查询名称
		rule.setChannelName(getChannelName(req.getChannelId()));
		
		
		String userId = req.getUserId();
		rule.setUserId(userId);
		SettleRulePersonalDO personRule = getRule(SettleTradeType.valueOf(req.getTradeType()),SettleType.valueOf(req.getSettleType()), userId, req.getChannelId(),null);
		
		//未查询到规则或者查询到的是通用规则
		if(personRule == null || StringUtils.isBlank(personRule.getUserId())){
			rule.setState((byte)req.getState());
			rule.setModifyTime(new Date());
			rulePersonalDao.save(rule);
			return rule.getId().intValue();
		}else{
			rule.setModifyTime(new Date());
			rule.setId(personRule.getId());
			return rulePersonalDao.update(rule);
		}
	}

	@Override
	public SettleRuleResponse queryUserSettleRule(SettleRuleRequest req) {
		ValidateUtil.isNotBlank(req.getUserId(), "userId不能为空");
		ValidateUtil.ge(req.getTradeType(), 1, "tradeType错误");
		ValidateUtil.notNull(req.getSettleType(), "settleType不能为空");
		SettleRulePersonalDO personRule = getRule(SettleTradeType.valueOf(req.getTradeType()),SettleType.valueOf(req.getSettleType()), req.getUserId(), req.getChannelId(),1);
		
		if(personRule == null || personRule.getUserId() == null){
			return null;
		}
		
		SettleRuleResponse response = new SettleRuleResponse();
		response.setUserId(personRule.getUserId());
		response.setFeeAmount(personRule.getFeeAmount());
		response.setFeeType(personRule.getFeeType());
		response.setLowerLimit(personRule.getLowerLimit());
		response.setSettleType(personRule.getSettleType());
		response.setState(personRule.getState());
		response.setTradeType(personRule.getTradeType());
		response.setUpperLimit(personRule.getUpperLimit());
		response.setOperator(personRule.getOperator());
		response.setChannelId(personRule.getChannelId());
		response.setChannelName(personRule.getChannelName());
		response.setModifyTime(personRule.getModifyTime());
		response.setAttach(personRule.getAttach());
		
		return response;
	}
	@Override
	public List<SettleRuleListResponse> querySettleRuleList(
			SettleRuleRequest req,PageQuery pageQuery) {

		SettleRulePersonalDO settleRulePersonalDO = new SettleRulePersonalDO();
		settleRulePersonalDO.setUserId(req.getUserId());
		settleRulePersonalDO.setTradeType((byte)req.getTradeType());
		settleRulePersonalDO.setState((byte)req.getState());
		settleRulePersonalDO.setChannelId(req.getChannelId());
		settleRulePersonalDO.setSettleType((byte)req.getSettleType());
		//查询渠道ID、用户ID限制条件
		List<SettleRuleIndexDO> ruleIndex = rulePersonalDao.getRuleIndex(settleRulePersonalDO,pageQuery);
		if(ruleIndex.size() == 0){
			SettleRuleIndexDO settleRuleIndexDO = new SettleRuleIndexDO();
			String tmpChannelId = req.getChannelId().equals("NA") ? "" : req.getChannelId();
			String tmpUserId = req.getUserId().equals("NA") ? "" : req.getUserId();
			settleRuleIndexDO.setChannelId(tmpChannelId);
			settleRuleIndexDO.setUserId(tmpUserId);
			ruleIndex.add(settleRuleIndexDO);
		}
		Log.info("ruleIndex:"+JSONObject.toJSONString(ruleIndex));
		//查询交易结算规则
		List<SettleRulePersonalListDO> ruleList = rulePersonalDao.getRuleList(settleRulePersonalDO,ruleIndex, pageQuery);
		
		if(ruleList == null){
			return null;
		}
		
		List<SettleRuleListResponse> response = new ArrayList<SettleRuleListResponse>();
		
		for (SettleRulePersonalListDO settleRulePersonalListDO : ruleList) {
			SettleRuleListResponse settleRuleList = new SettleRuleListResponse();
			String channelId = settleRulePersonalListDO.getChannelId();
			String userId = settleRulePersonalListDO.getUserId();
			int ruleType;
			if(!StringUtil.isBlank(userId)){
				ruleType = 1;
			}else if(!StringUtil.isBlank(channelId)){
				ruleType = 2;
			}else{
				ruleType = 3;
			}
			
			settleRuleList.setRuleType(ruleType);
			settleRuleList.setChannelId(channelId);
			settleRuleList.setUserId(userId);
			
			List<SettleRulePersonalDO> settleRulePersonalDOS = settleRulePersonalListDO.getSettleRulePersonalDOS();
			if(settleRulePersonalDOS.size() > 0){
				SettleRulePersonalDO tmpPersonalDO = settleRulePersonalDOS.get(0);
				
				settleRuleList.setModifyTime(tmpPersonalDO.getModifyTime());
				settleRuleList.setState(tmpPersonalDO.getState());
				settleRuleList.setOperator(tmpPersonalDO.getOperator());
				settleRuleList.setAttach(tmpPersonalDO.getAttach());
				settleRuleList.setChannelName(tmpPersonalDO.getChannelName());
			}
			
			
			List<SettleRuleResponse> tmpSettleRuleResponseList = new ArrayList<SettleRuleResponse>();
			for (SettleRulePersonalDO rulePersonalDO : settleRulePersonalDOS) {
				SettleRuleResponse tmpSettleRuleResponse = new SettleRuleResponse();
				
				tmpSettleRuleResponse.setUserId(rulePersonalDO.getUserId());
				tmpSettleRuleResponse.setFeeAmount(rulePersonalDO.getFeeAmount());
				tmpSettleRuleResponse.setFeeType(rulePersonalDO.getFeeType());
				tmpSettleRuleResponse.setLowerLimit(rulePersonalDO.getLowerLimit());
				tmpSettleRuleResponse.setSettleType(rulePersonalDO.getSettleType());
				tmpSettleRuleResponse.setState(rulePersonalDO.getState());
				tmpSettleRuleResponse.setTradeType(rulePersonalDO.getTradeType());
				tmpSettleRuleResponse.setUpperLimit(rulePersonalDO.getUpperLimit());
				tmpSettleRuleResponse.setOperator(rulePersonalDO.getOperator());
				tmpSettleRuleResponse.setChannelId(rulePersonalDO.getChannelId());
				tmpSettleRuleResponse.setChannelName(rulePersonalDO.getChannelName());
				tmpSettleRuleResponse.setModifyTime(rulePersonalDO.getModifyTime());
				tmpSettleRuleResponse.setAttach(rulePersonalDO.getAttach());
				tmpSettleRuleResponse.setId(rulePersonalDO.getId());
				
				
				tmpSettleRuleResponseList.add(tmpSettleRuleResponse);
			}
			
			settleRuleList.setSettleRuleResponse(tmpSettleRuleResponseList);
			
			response.add(settleRuleList);
		}
		return response;
	}

	@Override
	public Integer querySettleRuleCount(SettleRuleRequest req) {
		SettleRulePersonalDO settleRulePersonalDO = new SettleRulePersonalDO();
		settleRulePersonalDO.setUserId(req.getUserId());
		settleRulePersonalDO.setTradeType((byte)req.getTradeType());
		settleRulePersonalDO.setState((byte)req.getState());
		settleRulePersonalDO.setChannelId(req.getChannelId());
		settleRulePersonalDO.setSettleType((byte)req.getSettleType());
		//查询交易结算规则
		Integer ruleCount = rulePersonalDao.getRuleCount(settleRulePersonalDO);
		return ruleCount;
	}

	@Override
	public void configSettleRules(SettleRuleListRequest list,int type) {
		if(!StringUtil.isBlank(list.getUserId()) && StringUtil.isBlank(list.getChannelId())){
			String channelId = getChannelIdByUserId(list.getUserId());
			list.setChannelId(channelId);
		}
		SettleRuleRequest req = new SettleRuleRequest();
		String channelId = list.getChannelId();
		channelId = StringUtil.isBlank(channelId) ? "NA" : channelId;
		req.setChannelId(channelId);
		String userId = list.getUserId();
		userId = StringUtil.isBlank(userId) ? "NA" : userId;
		req.setUserId(userId);
		List<SettleRuleListResponse> ruleListResponse = querySettleRuleList(req , null);
		if(ruleListResponse.size() > 1){
			throw new BusinessException("系统查询结算规则出错!");
		}
		SettleRuleListResponse ruleResponse = null;
		if(ruleListResponse != null && ruleListResponse.size() == 1){
			ruleResponse = ruleListResponse.get(0);
		}
		boolean needCompare = false;
		if(ruleResponse == null){
			needCompare = false;
		}else if(type == 1 && !StringUtil.isBlank(ruleResponse.getUserId())){
			needCompare = true;
		}else if(type == 2 && !StringUtil.isBlank(ruleResponse.getChannelId())){
			needCompare = true;
		}else if(type == 3 && StringUtil.isBlank(ruleResponse.getChannelId())){
			needCompare = true;
		}
		saveOrUpdateList(list,ruleResponse,needCompare);
	}
	
	/**
	 * 
	 * @param list   接口规则数据
	 * @param ruleResponse	数据库中规则数据列表
	 * @param needCompare 是否对数据库中规则对应的交易类型与接口中的交易类型进行比较   从而确定是插入还是更新
	 */
	private void saveOrUpdateList(SettleRuleListRequest list,SettleRuleListResponse ruleResponse,boolean needCompare){
		//需要保存的list
		List<SettleRulePersonalDO> insertList = new ArrayList<SettleRulePersonalDO>();
		//需要更新的list
		List<SettleRulePersonalDO> updateList = new ArrayList<SettleRulePersonalDO>();
		
		List<SettleRuleRequest> ruleList = list.getList();
		
		//数据库查询到的当前权限数据
		List<SettleRuleResponse> settleRuleResponse = null;
		if(ruleResponse != null){
			settleRuleResponse = ruleResponse.getSettleRuleResponse();
		}
		String channelName = null;
		if(!StringUtil.isBlank(list.getChannelId())){
			channelName = getChannelName(list.getChannelId());
		}
		for (SettleRuleRequest reuqest : ruleList){
			int reqTradeType = reuqest.getTradeType();
			boolean tmpSaveFlag = true;
			SettleRulePersonalDO ruleDO = new SettleRulePersonalDO();
			
			ruleDO.setFeeAmount(reuqest.getFeeAmount());
			ruleDO.setFeeType((byte)reuqest.getFeeType());
			ruleDO.setLowerLimit((int)reuqest.getLowerLimit());
			ruleDO.setSettleType((byte)reuqest.getSettleType());
			ruleDO.setState((byte)reuqest.getState());
			ruleDO.setTradeType((byte)reuqest.getTradeType());
			ruleDO.setUpperLimit((int)reuqest.getUpperLimit());
			ruleDO.setAttach(list.getAttach());
			ruleDO.setOperator(list.getOperator());
			ruleDO.setChannelId(list.getChannelId());
			ruleDO.setModifyTime(new Date());
			if(needCompare){
				for (SettleRuleResponse tmpRuleResponse : settleRuleResponse){
					int tmpTradeType = tmpRuleResponse.getTradeType();
					if(tmpTradeType == reqTradeType){
						ruleDO.setId(tmpRuleResponse.getId());
						updateList.add(ruleDO);
						tmpSaveFlag = false;
						break;
					}
				}	
			}
			
			if(tmpSaveFlag){
				ruleDO.setChannelName(channelName);
				ruleDO.setUserId(list.getUserId());
				insertList.add(ruleDO);
			}
		}
		
		batchSave(insertList);
		update(updateList);
		
	}
	
	
	
	private void batchSave(List<SettleRulePersonalDO> insertList){
		if(insertList.size() > 0){
			rulePersonalDao.batchSave(insertList);
		}
	}
	private void update(List<SettleRulePersonalDO> insertList){
		for (SettleRulePersonalDO settleRulePersonalDO : insertList) {
			rulePersonalDao.update(settleRulePersonalDO);
		}
	}

	@Override
	public void cancleRule(String channelId, String userId) {
		if(StringUtil.isBlank(channelId) && StringUtil.isBlank(userId)){
			throw new BusinessException("渠道ID和用户不能全为空");
		}
		channelId = StringUtil.isBlank(channelId) ? "NA" : channelId;
		userId = StringUtil.isBlank(userId) ? "NA" : userId;
		SettleRulePersonalDO settleRulePersonalDO = new SettleRulePersonalDO();
		settleRulePersonalDO.setChannelId(channelId);
		settleRulePersonalDO.setUserId(userId);
		settleRulePersonalDO.setState(new Byte("3"));
		
		rulePersonalDao.cancel(settleRulePersonalDO );
	}

	@Override
	public List<SettleOrderDO> queryOrderSettle(QuerySettle query,
			PageQuery pageQuery) {
		
		return settleOrderDao.findSettleOrder(query, pageQuery);
	}

	@Override
	public int countOrderSettle(QuerySettle query) {
		
		return settleOrderDao.countSettleOrder(query);
	}
	
	
	/**
	 *  bank.pay.rule=1|100|100000|0|0
		weixin.pay.rule=2|0.3|0|0|0
		alipay.pay.rule=2|0.6|0|0|0
		quick.debit.pay.rule=1|100|100000|0|0
		quick.credit.pay.rule=2|0.4|100000|0.1|0
	 * @param bankId
	 * @param cardType
	 * @return
	 */
	private long getJFPayFee(SettleTradeType tradeType,long amount,String bankId,CardType cardType){
		long fee = 0;
		String rule = null;
		if(StringUtil.isBlank(bankId) || tradeType == SettleTradeType.TRADE){
			return fee;
		}
		String startWith = bankId.substring(0, 1);
		if(startWith.equals("0")){
			return fee;
		}else if(bankId.equals("3000004")){
			rule = JfConfigUtil.getConfig("alipay.pay.rule");
		}else if(bankId.equals("3000005")){
			rule = JfConfigUtil.getConfig("weixin.pay.rule");
		}else if(bankId.equals("1100000")){
			rule = JfConfigUtil.getConfig("union.pay.rule");
		}else if(startWith.equals("1")){
			rule = JfConfigUtil.getConfig("bank.pay.rule");
		}else if(startWith.equals("2")){
			if(cardType == CardType.CARD_DEBIT){
				rule = JfConfigUtil.getConfig("quick.debit.pay.rule");
			}else{
				rule = JfConfigUtil.getConfig("quick.credit.pay.rule");
			}
		}

		if(rule == null){
			return fee;
		}
		fee = getFeeByRule(amount, rule);
		
		return fee;
	}
	//feetype|feeamount|freefeemaxamount|lowerlimitfee|upperlimitfee
	private long getFeeByRule(long amount,String rule){
		String[] ruleArr = rule.split("\\|");
		int feetype = Integer.parseInt(ruleArr[0]);
		double feeamount = Double.valueOf(ruleArr[1]);
		int freefeemaxamount = Integer.parseInt(ruleArr[2]);
		double lowerlimitfee = Double.valueOf(ruleArr[3]);
		double upperlimitfee = Double.valueOf(ruleArr[4]);
		
		double fee = 0;
		if(freefeemaxamount != 0 && amount >= freefeemaxamount){
			return 0;
		}
		
		if(feetype == 1){
			fee = feeamount;
		}else if(feetype == 2){
			fee = amount * feeamount / 100;
		}
		
		if(lowerlimitfee != 0 && lowerlimitfee > fee){
			fee = lowerlimitfee;
		}
		
		if(upperlimitfee != 0 && upperlimitfee < fee){
			fee = upperlimitfee;
		}
		
		return Double.valueOf(fee).longValue();
	}
	/**
	 * 缴费检查白名单
	 * @param userId
	 * @return
	 */
	private boolean checkInWhiteList(String userId){
		String whiteListStr = JfConfigUtil.getConfig("jf.white.list");
		if(StringUtil.isBlank(whiteListStr)){
			return false;
		}
		String[] whiteArr = whiteListStr.split(",");
		List<String> whiteList = Arrays.asList(whiteArr);
		if(whiteList.contains(userId)){
			return true;
		}else{
			return false;
		}
	}
//	public static void main(String[] args) {
//		double fee = 1.5;
//		long longValue = Double.valueOf(fee).longValue();
//		System.err.println(longValue);
//	}

	@Override
	public void settlingOrders() {
		log.info("开始结算");
		String today = DateUtil.formatDate(new Date(), DateUtil.SHORT_DATE_FORMAT_STR);
		boolean lockState = lockRedisDAO.lockSettleOrder(today, 60 * 60 * 12);
		if (!lockState) { 
			log.info("时间:{}重复发起结算,直接返回!",today);
			return;
		}
		// 扫描未结算的定时结算订单
		Calendar cal = Calendar.getInstance();
		cal.add(Calendar.DAY_OF_MONTH, 1);
		cal.set(Calendar.HOUR_OF_DAY, 0);
		cal.set(Calendar.MINUTE, 0);
		cal.set(Calendar.SECOND, 0);
		Date settleTime = cal.getTime();

		int count = settleOrderDao.countSettleLaterOrders(settleTime);
		if (count <= 0) {
			lockRedisDAO.unLockSettleOrder(today);
			log.info("时间:{}解锁结算任务",today);
			return;
		} else {
			int pageSize = 1000;
			int totalPage = (count / pageSize) + 1;
			for (int pageNo = 1; pageNo <= totalPage; pageNo++) {
				PageQuery page = new PageQuery(pageNo, pageSize);
				List<SettleOrderDO> orders = settleOrderDao.getSettleLaterOrders(settleTime, page);

				log.info(String.format("[%s]前未结算的定时结算订单第%s页共%s", settleTime, pageNo, orders.size()));

				for (SettleOrderDO order : orders) {
						// 修改订单状态至结算中
						List<SettleOrderDO> settleOrders = new ArrayList<SettleOrderDO>();
						String settleDetailsStr = order.getSettleDetail();
						String[] settleDetailsArr = settleDetailsStr.split(",");
						for (String settleDetail : settleDetailsArr) {
							String[] split = settleDetail.split("\\|");
							SettleOrderDO settleOrder = new SettleOrderDO();
							BeanUtils.copyProperties(order, settleOrder);
							settleOrder.setPayeeUser(split[0]);
							settleOrder.setSettleAmount(Long.valueOf(split[1]));
							settleOrder.setTradeOrderType(Integer.valueOf(split[2]));
							settleOrders.add(settleOrder);
						}
						settleOrderDao.updateStateByOrderId(order.getOrderId(), SettleState.SETTLING.getValue());
						log.info("结算订单:" + JSONObject.toJSONString(settleOrders));
						transfer(order.getOrderId(), settleOrders);
				}
			}
			log.info("时间:{}解锁结算任务",today);
			lockRedisDAO.unLockSettleOrder(today);
		}
	}
	
}
